<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // 获取随机数 => 异步版,返回Promise实例(pending) 指定时间之后可以变为fulfilled/rejected
    function getNumAsync(num, delay = 0, isFulfilled = true) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                isFulfilled ? resolve(num) : reject(num);
            }, delay);
        })
    }

    // 如果多个异步操作之间不相互依赖,同时启动多个异步操作,按顺序返回结果
    // var p1 = getNumAsync(1, 2000); // 2s
    // var p2 = getNumAsync(2, 1000); // 1s
    // var p3 = getNumAsync(3, 3000); // 3s

    // var list = []
    // p1.then((res) => {
    //     console.log("fulfilled", res);
    //     return p2;
    // }).then((res) => {
    //     console.log("fulfilled", res);
    //     return p3; // 3s
    // }).then(res => {
    //     console.log("fulfilled", res);
    // }).catch(err => {
    //     console.log("rejected", err);
    // })

    // 上述代码,同时启动三个异步操作(全部都有结果,最多耗时3s) =>  p1状态改变需要2s => 执行then方法,此时p2状态已经改变, 继续向后调用then()方法, 再等待1s,p3的状态也会改变  => 总共耗3s
    // 缺点: 虽然多个异步操作同时启动,但是还需要通过链式操作,执行数据返回顺序  => 麻烦


    /* 
        构造函数Promise的方法  => 构造函数Promise自己用
        Promise.all(list) 方法用于将多个 Promise 实例，包装成一个新的 Promise 实例。
        var p = Promise.all([p1,p2,p3]);

        Promise.all()方法接受一个数组作为参数，p1、p2、p3都是 Promise 实例，如果不是，就会先调用下面讲到的Promise.resolve方法，将参数转为 Promise 实例，再进一步处理

        p的状态由p1、p2、p3决定，分成两种情况。

        （1）只有p1、p2、p3的状态都变成fulfilled，p的状态才会变成fulfilled，此时p1、p2、p3的存储的数据组成一个数组，传递给p(存储到新的Promise实例中)。

        （2）只要p1、p2、p3之中有一个被rejected，p的状态就变成rejected，此时第一个被reject的实例的返回值，会传递给p的回调函数。

        // 技巧: 全都成功才成功,有一个失败就失败  (全都成功,总的事件按最慢的来)


        Promise.race(list) 方法用于将多个 Promise 实例，包装成一个新的 Promise 实例。
        var p = Promise.race([p1,p2,p3]);
        新的Promise实例的状态和数据,依赖于最先改变状态的Promise实例(p1, p2 , p3)

        // 技巧: 多个异步操作中,最快的那一个(无论成功/失败)\
        

        Promise.any(list) 方法用于将多个 Promise 实例，包装成一个新的 Promise 实例。
        var p = Promise.any([p1,p2,p3]);
        ES2021 引入了Promise.any()方法。该方法接受一组 Promise 实例作为参数，包装成一个新的 Promise 实例返回。

        p1,p2,p3中, 只要Promise实例有一个变成fulfilled状态，包装实例就会变成fulfilled状态；如果所有参数实例都变成rejected状态，包装实例就会变成rejected状态。

        技巧: 有一个成功就成功(找最快成功的那个),全都失败才失败


        有时候，我们希望等到一组异步操作都结束了，不管每一个操作是成功还是失败，再进行下一步操作。
        Promise.allSettled(list) 方法用于将多个 Promise 实例，包装成一个新的 Promise 实例。
        var p = Promise.allSettled([p1,p2,p3]);
        ES2020 引入了Promise.allSettled()方法，用来确定一组异步操作是否都结束了（不管成功或失败）

        新的Promise实例状态,会在p1,p2,p3全都有结果之后变为已成功, 并接收p1,p2,p3中存储的结果放到数组中  
        为了区分p1,p2,p3每一个Promise实例的结果  => 在数组中存储的是一个对象
        成功:{status:"fulfilled",value:xxxx}
        失败:{status:"rejected",reason:xxxx}

    
     */


    /* var p1 = getNumAsync(1, 2000); // 2s
    var p2 = getNumAsync(2, 1000); // 1s
    var p3 = getNumAsync(3, 3000, false); // 3s

    var p = Promise.allSettled([p1, p2, p3])
    console.log("新的Promise实例p", p);

    p.then(list => {
        console.log("异步操作都结束了", list);
    }).catch(err => {
        console.log("失败", err);
    }) */





    // 模拟封装
    Promise.myAllSettled = function (list) { // [p1(2s), p2(1s), p3(3s)]
        return new Promise(function (resolve, reject) { // 新的Promise实例
            var count = 0;
            var arr = [];
            for (let i = 0; i < list.length; i++) {  // 遍历数组 
                let item = list[i]; // 每一个Promise实例
                item.then(res => {  // 因为 p1,p2,p3是异步操作  => then/catch对应的回调函数执行时也是异步(问题: i 是跳出循环的值 i = 3 )
                    count++;  // 无论成功还是失败都会计数 => 统计异步操作执行了几个

                    arr[i] = { status: "fulfilled", value: res };
                    if (count == list.length) {
                        resolve(arr);
                    }

                }).catch(err => {
                    count++;   // 无论成功还是失败都会计数 => 统计异步操作执行了几个
                    arr[i] = { status: "rejected", reason: err };
                    if (count == list.length) {
                        resolve(arr);
                    }
                })
            }

        })
    }


    var p1 = getNumAsync(1, 2000); // 2s
    var p2 = getNumAsync(2, 1000, false); // 1s
    var p3 = getNumAsync(3, 3000); // 3s

    var p = Promise.myAllSettled([p1, p2, p3])
    console.log("新的Promise实例p", p);

    p.then(list => {
        console.log("异步操作都结束了", list);
    }).catch(err => {
        console.log("失败", err);
    })














</script>

</html>